package xq.gwt.mvc.model;
import java.io.Serializable;
import java.util.ArrayList;

public abstract class AbstractEntityModel implements EntityModel, Serializable {
	protected EntityArrayPropertyModel[] childEntities;	
	private static final long serialVersionUID = 1495004083771864169L;
	transient private ArrayList<EntityChangedListener> listeners = new ArrayList<EntityChangedListener>();
	
	public void addEntityChangedListener(EntityChangedListener listener){
		if(listener != null)
			listeners.add(listener);
	}
	
	public void removeEntityChangedListener(EntityChangedListener listener){
		listeners.remove(listener);
	}
	
	public void removeAllEntityChangedListeners(){
		listeners.clear();
	}
	
	public void detatchEntity(){
		removeAllEntityChangedListeners();
		for (int i = 0; i < getProperties().length; i++) {
			getProperties()[i].removeAllPropertyChangedListeners();
		}
	}
	
	protected void notifyEnityChanged(){			
		for (int i = 0; i < listeners.size(); i++) {
			EntityChangedListener listener = listeners.get(i);
			if (listener != null){
				EntityChangedEvent event = new EntityChangedEvent(this);
				listener.entityChanged(event);
			}				
		}		 
	}
	
	public String getName(){
		return this.getClass().getName();
	}
	
	@Override
	public String getIdentifier(){
		return String.valueOf(hashCode());
	}
	
	@Override
	public boolean isValid(){
		if (getProperties() == null)
			return true;
		for(PropertyModel prop : getProperties()){
			if(!prop.isValid())
				return false;
		}		
		return true;
	}

	@Override
	public PropertyModel getProperty(String name) {
		if (getProperties() == null)
			return null;
		if(name == null)
			return null;
		for(PropertyModel prop : getProperties()){
			if(name.equals(prop.getName()))
				return prop;
		}
		return null;
	}

	public abstract EntityModel newInstance();
	
	public EntityModel copy()throws Exception{
		EntityModel newEntity = newInstance();		
		copyPropertyValues(this, newEntity);				
		return newEntity;
	}
	
	protected void copyPropertyValues(EntityModel fromEntity, EntityModel toEntity) throws Exception{		
		copyPropertyValues(fromEntity.getProperties(), toEntity.getProperties());
	}
	
	protected void copyPropertyValues(PropertyModel[] fromProps,PropertyModel[] toProps) throws Exception{
		if (fromProps != null){
			for (int i = 0; i < fromProps.length; i++) {				
				if(fromProps[i] instanceof EntityArrayPropertyModel){
					copyEntityArrayPropVal((EntityArrayPropertyModel)fromProps[i], (EntityArrayPropertyModel)toProps[i]);
				} else {
					toProps[i].setText(fromProps[i].getText());
				}
				
				toProps[i].setHidden(fromProps[i].isHidden());
				toProps[i].setReadonly(fromProps[i].isReadonly());
				toProps[i].setRequired(fromProps[i].isRequired());
				toProps[i].setValueItems(fromProps[i].getValueItems());
			}
		}
	}
	
	private void copyEntityArrayPropVal(EntityArrayPropertyModel fromProp, EntityArrayPropertyModel toProp) throws Exception{		
		if(fromProp.getValue() == null){
			toProp.setValue(null);
			return;
		}
		
		EntityModel[] copiedEntities = new EntityModel[fromProp.getValue().length];
		for (int i = 0; i < fromProp.getValue().length; i++) {
			EntityModel entity = fromProp.getValue()[i];
			if(entity != null){
				copiedEntities[i] = entity.copy();
			}			
		}
		toProp.setValue(copiedEntities);		
	}

	@Override
	public boolean hasRelations() {
		for (PropertyModel property : getProperties()) {
			if(property.getRelation() != null){
				return true;
			}
		}
		return false;
	}
	
	
}
